from weakref import ref

from kivy.properties import ObjectProperty, OptionProperty


class TogglePlayBehavior:
    """
    同一组的音乐不能同时播放
    """

    play_state = OptionProperty('stop', options=["stop", "play", "pause"])

    __groups = {}

    group = ObjectProperty(None, allownone=True)
    """Group of the button. If `None`, no group will be used (the button will be
    independent). If specified, :attr:`group` must be a hashable object, like
    a string. Only one button in a group can be in a 'down' state.

    :attr:`group` is a :class:`~kivy.properties.ObjectProperty` and defaults to
    `None`.
    """

    def __init__(self, **kwargs):
        self._previous_group = None
        super(TogglePlayBehavior, self).__init__(**kwargs)

    def on_group(self, *args):
        _ = args
        groups = TogglePlayBehavior.__groups
        if self._previous_group:
            group = groups[self._previous_group]
            for item in group[:]:
                if item() is self:
                    group.remove(item)
                    break
        group = self._previous_group = self.group
        if group not in groups:
            groups[group] = []
        r = ref(self, TogglePlayBehavior._clear_groups)
        groups[group].append(r)

    def _release_group(self, current):
        if self.group is None:
            return
        group = self.__groups[self.group]
        for item in group[:]:
            widget = item()
            if widget is None:
                group.remove(item)
            # 除自己外 其他暂停播放
            if widget is current:
                continue
            if current.play_state == 'play' and widget.group == self.group and widget.is_playing():
                widget.stop_play()
                widget.play_state = 'pause'
                widget.on_pause_or_proceed_update_ui()
            elif (current.play_state in ('pause', 'stop') and widget.group == self.group
                  and widget.track_type == 'primary' and widget.play_state == 'pause'):
                widget.proceed_play()
                widget.on_pause_or_proceed_update_ui()
                break

    def _toggle_do_play(self):
        if self.group and self.play_state == 'play':
            return

        self.play_state = 'play'
        self._release_group(self)

    def _toggle_do_pause(self):
        if self.group and self.play_state == 'pause':
            return

        self.play_state = 'pause'
        self._release_group(self)

    def _toggle_do_stop(self):
        if self.group and self.play_state == 'stop':
            return

        self.play_state = 'stop'
        self._release_group(self)

    @staticmethod
    def _clear_groups(wk):
        # auto flush the element when the weak reference have been deleted
        groups = TogglePlayBehavior.__groups
        for group in list(groups.values()):
            if wk in group:
                group.remove(wk)
                break

    @staticmethod
    def get_widgets(group_name):
        """Return a list of the widgets contained in a specific group. If the
        group doesn't exist, an empty list will be returned.

        note::

            Always release the result of this method! Holding a reference to
            any of these widgets can prevent them from being garbage collected.
            If in doubt, do::

                l = TogglePlayBehavior.get_widgets('my_group')
                # do your job
                del l

        warning::

            It's possible that some widgets that you have previously
            deleted are still in the list. The garbage collector might need
            to release other objects before flushing them.
        """
        groups = TogglePlayBehavior.__groups
        if group_name not in groups:
            return []
        return [x() for x in groups[group_name] if x()][:]
